#include "bits/stdc++.h"
using namespace std;
using ll = long long;
// 按照边权排序后
// 1.一个强大的性质：建树时候[u, v]的边权w，等于新建点P的点权，求路径边权等于求这个lca的点权
// 2.新建点最多为n - 1个，因此该树最多2 * n - 1个点
// 3.注意所有新建点都不是叶子节点，即原始点全为叶子节点
// 4.如果是建最小生成树，则可以O(logn)求[u, v]路径的最大边权
// 5.如果是建最大生成树，则可以O(logn)求[u, v]路径的最小边权
struct DSU {
	DSU(int n) : siz_(n + 1), father_(n + 1), connected_blocks_(n) {
		for (int i = 1; i <= n; i++) {
			siz_[i] = 1;
			father_[i] = i;
		}
	}
	DSU() {}

	int find(int x) {
		return x == father_[x] ? x : father_[x] = find(father_[x]);
	} 

	void merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return;
		}
		father_[x] = y;
		siz_[y] += siz_[x];
		connected_blocks_--;
	}

	vector<int> siz_, father_;
	int connected_blocks_;
};

struct KruscalTree {
	KruscalTree(int n) : n_(n), dsu_(2 * n + 1), W_(2 * n + 1, -1), dep_(2 * n + 1, 0), g_(2 * n + 1), f_(2 * n + 1) {
		m_ = __lg(n) + 2;
		for (int i = 0; i <= 2 * n; i++) {
			f_[i].resize(m_);
			g_[i].clear();
		}
	}

	void addEdge(int u, int v, int w = 0) {
		u = dsu_.find(u), v = dsu_.find(v);
		if (u == v) {
			return;
		}
		n_++;
		g_[n_].push_back(u);
		g_[n_].push_back(v);
		dsu_.merge(u, n_);
		dsu_.merge(v, n_);
		W_[n_] = w;
	}

	void dfs(int u, int f) {
		dep_[u] = dep_[f] + 1;
		f_[u][0] = f;
		for (int i = 1; i < m_; i++) {
			f_[u][i] = f_[f_[u][i - 1]][i - 1];
		}
		for (auto &v : g_[u]) {
			dfs(v, u);
		}
	}

	void work() {
		for (int i = n_; i >= 1; i--) {
			if (!dep_[i]) {
				dfs(i, 0);
			}
		}
	}

	int lca(int u, int v) {
		if (dep_[u] < dep_[v]) {
			swap(u, v);
		}
		int d = dep_[u] - dep_[v];
		for (int i = m_ - 1; i >= 0; i--) {
			if (d >> i & 1) {
				u = f_[u][i];
			}
		}

		if (u == v) {
			return u;
		}

		for (int i = m_ - 1; i >= 0; i--) {
			if (f_[u][i] != f_[v][i]) {
				u = f_[u][i];
				v = f_[v][i];
			}
		}
		return f_[u][0];
	}

  void setWeight(int x, int w) {
		W_[x] = w;
	}

	int getWeight(int x, int y) {
		return W_[lca(x, y)];
	}

	int n_, m_;
	DSU dsu_;
	vector<int> W_, dep_;
	vector<vector<int>> g_, f_;
};

struct edge {
  int u, v, w;
  bool operator<(const edge& other) const {
    return w > other.w;
  }
};
void solve()
{
  int n, m;
  cin >> n >> m;

  vvi f(n + 1, vi(m + 1));
  KruscalTree kt(n * m);

  auto id = [&](int x, int y) {
    return (x - 1) * m + y;
  };

  vector<edge> e;
  auto addEdge = [&](int u, int v, int w) {
    e.pb({u, v, w});
  };
  rep(i, 1, n) {
    rep(j, 1, m) {
      cin >> f[i][j];
      if (i > 1) {
        addEdge(id(i, j), id(i - 1, j), min(f[i][j], f[i - 1][j]));
      }
      if (j > 1) {
        addEdge(id(i, j), id(i, j - 1), min(f[i][j], f[i][j - 1]));
      }
    }
  }
  sort(all(e));
  for (auto &i : e) {
    kt.addEdge(i.u, i.v, i.w);
  }
  rep(i, 1, n) {
    rep(j, 1, m) {
      kt.setWeight(id(i, j), f[i][j]);
    }
  }
  kt.work();

  int q;
  cin >> q;
  while (q--) {
    int x1, y1, f1;
    int x2, y2, f2;
    cin >> x1 >> y1 >> f1;
    cin >> x2 >> y2 >> f2;

    int u = id(x1, y1), v = id(x2, y2);
    int w = kt.getWeight(u, v);
    int mi = min({w, f1, f2});
    cout << abs(f1 - mi) + abs(f2 - mi) << '\n';
  }
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	while (_--) {
		solve();
	}
	return 0;
}